package org.finesys.common.security.core.service.impl;

import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.finesys.common.constants.SecurityConstants;
import org.finesys.common.core.exception.BusinessException;
import org.finesys.common.core.module.ROpt;
import org.finesys.system.api.dto.ClientDetailsDto;
import org.finesys.system.api.service.ClientService;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat;
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
import org.springframework.util.StringUtils;

import java.time.Duration;
import java.util.Arrays;
import java.util.Optional;

@RequiredArgsConstructor
public class AuthRegisteredClientRepository implements RegisteredClientRepository {
    private final ClientService clientService;
    /**
     * 请求令牌有效期默认 8 小时
     */
    private Integer ACCESS_TOKEN_VALIDITY_SECONDS = 60 * 60 * 8;
    /**
     * 刷新令牌有效期默认 8 小时
     */
    private Integer REFRESH_TOKEN_VALIDITY_SECONDS = 60 * 60 * 8;


    @Override
    public void save(RegisteredClient registeredClient) {

    }

    @Override
    public RegisteredClient findById(String id) {
        throw new UnsupportedOperationException();
    }


    @Override
    @SneakyThrows
    public RegisteredClient findByClientId(String clientId) {
        //获取客户端数据
        ClientDetailsDto clientDetailsDto = ROpt.ofNullable(clientService.getByClientId(clientId))
                .assertSuccess(r -> new BusinessException(String.format("客户端ClientID不存在：%s,%s", clientId, r.getMsg())))
                .peek().getData();
        //返回客户端注册信息
        return getRegisteredClient(clientDetailsDto);
    }


    private RegisteredClient getRegisteredClient(ClientDetailsDto clientDetailsDto) {
        RegisteredClient.Builder builder = RegisteredClient
                // 注册标识符
                .withId(String.valueOf(clientDetailsDto.getId()))
                //客户端id
                .clientId(clientDetailsDto.getClientId())
                //客户端密钥
                .clientSecret(SecurityConstants.NOOP + clientDetailsDto.getClientSecret())
                //身份验证方法
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
                .clientAuthenticationMethods(clientAuthenticationMethods -> {
                    clientAuthenticationMethods.add(ClientAuthenticationMethod.CLIENT_SECRET_BASIC);
                    clientAuthenticationMethods.add(ClientAuthenticationMethod.CLIENT_SECRET_POST);
                });
        //授权模式
        Optional.ofNullable(clientDetailsDto.getAuthorizedGrantTypes())
                .ifPresent(grant -> StringUtils.commaDelimitedListToSet(grant)
                        .forEach(s -> builder.authorizationGrantType(new AuthorizationGrantType(s))));
        //回调地址
        Optional.ofNullable(clientDetailsDto.getWebServerRedirectUri())
                .ifPresent(redirectUri -> Arrays.stream(redirectUri.split(StrUtil.COMMA))
                        .filter(StrUtil::isNotBlank)
                        .forEach(builder::redirectUri));
        //scope
        Optional.ofNullable(clientDetailsDto.getScope())
                .ifPresent(scope -> Arrays.stream(scope.split(StrUtil.COMMA))
                        .filter(StrUtil::isNotBlank)
                        .forEach(builder::scope)
                );
        //配置项信息
        builder.tokenSettings(TokenSettings.builder()
                //刷新token
                .accessTokenFormat(OAuth2TokenFormat.REFERENCE)
                //令牌有效期
                .accessTokenTimeToLive(Duration.ofSeconds(Optional.ofNullable(clientDetailsDto.getAccessTokenValidity()).orElse(ACCESS_TOKEN_VALIDITY_SECONDS)))
                //刷新令牌有效期
                .refreshTokenTimeToLive(Duration.ofSeconds(Optional.ofNullable(clientDetailsDto.getRefreshTokenValidity()).orElse(REFRESH_TOKEN_VALIDITY_SECONDS))).build());
        //客户端配置
        builder.clientSettings(ClientSettings.builder()
                .requireAuthorizationConsent(!BooleanUtil.toBoolean(clientDetailsDto.getAutoApprove()))
                .build());
        return builder.build();

    }
}
